#include "stdafx.h"
#include "CScrLanguage.h"
#include "CScripts.h"
#include "CDecompiler.h"

using namespace std;

string		CDecompiler::s_sBuffer;
CLabel	*	CDecompiler::s_pCurrentLabel,
		*	CDecompiler::s_pLastPrintedLabel;
CSubScript* CDecompiler::s_pSubScript;
BYTE	*	CDecompiler::s_pInBuffer,
		*	CDecompiler::s_pInCurrent;
FILE	*	CDecompiler::s_hInFile,
		*	CDecompiler::s_hOutFile;
tOpcode		CDecompiler::s_sLastOpcode;
char		CDecompiler::s_szStringParam[],
			CDecompiler::s_szScriptName[]			= "noname";
uParam		CDecompiler::s_Params[],
			CDecompiler::s_Returns[];
ArrayVar	CDecompiler::s_ArrayVar;
bool		CDecompiler::s_bDoNewLine,
			CDecompiler::s_bOr,
			CDecompiler::s_bNot,
			CDecompiler::s_bSecondPass;
int			CDecompiler::s_nTotalNumConditions,
			CDecompiler::s_nNumConditions,
			CDecompiler::s_nNumBytesRead,
			CDecompiler::s_nNumLinesWritten,
			CDecompiler::s_nNumReturns,
			CDecompiler::s_nNumParams,
			CDecompiler::s_nIndentLevels,
			CDecompiler::s_nInputSize;
DWORD		CDecompiler::s_dwOpcodeBeginOffset,
			CDecompiler::s_dwScriptBeginOffset		= 0,
			CDecompiler::s_dwCurrentOffset;

int CDecompiler::Decompile(FILE * hInFile, FILE * hOutFile)
{
	/*g_pScript = new CScript(hInFile);
	Init(hInFile, hOutFile);

	s_bSecondPass = false;

	// 1st pass
	while(!IsEnd()) DecompileLine();

	s_bSecondPass = true;

	// Final pass
	if(CLabel * pLabel = CLabels::GetFirstLabel())
	{
		do
		{
			if(pLabel->WasSkippedOnFirstPass())
			{
				SetPC(pLabel->GetStart());
				s_pCurrentLabel = pLabel;
				while(!IsEnd()) DecompileLine(); 
			}
		}
		while(pLabel = pLabel->GetNext());
	}

	Finalize();

	return s_nNumBytesRead;*/
	return 0;
}

void CDecompiler::DecompileLine()
{
	CCommand *pCommand;
	COperation *pOperation;
	COpcode *pOpcode;
	
	static int num_hex_bytes = 0;

	Preline();

	if(pOpcode = ReadOpcode())
	{
		int numParams = 0,
			numReturns = 0,
			opcodeType = pOpcode->GetType();
		tDataType type;

		if(num_hex_bytes && opcodeType != OPCODE_TYPE_UNKNOWN)
		{
			OutputNewline();
				num_hex_bytes = 0;
			Output("ENDHEX");
			OutputNewline();
		}

		OutputLogicalOperator(pOpcode);

		switch(opcodeType)
		{
		case OPCODE_TYPE_UNKNOWN:
			//break;
		case OPCODE_TYPE_COMMAND:
			if(pCommand = pOpcode->Get<CCommand>())
			{
				if(COperation *pOperation = pCommand->GetOperation())
				{
					char op[MAX_OPERATOR_CHARS+1];
					pOperation->GetOperator()->GetOperatorString(op);
					type = ReadDataType();
					uParam *p = StoreParam(type);
					OutputParam(type, p);
					Output(op);
					Output(pCommand->GetName());
					if(numParams = pCommand->GetNumParams())
						ProcessCommand(pOpcode, numParams, 0);
					if(numReturns = pCommand->GetNumReturns())
						ProcessCommand(pOpcode, numReturns, 1);
				}
				else
				{
					if(opcodeType != OPCODE_TYPE_UNKNOWN)
					{
						Output(pCommand->GetName());
					}
					else
					{
						//sprintf(g_szTempString, "UNKNOWN_%04X", s_sLastOpcode);
						strcpy(g_szTempString, "UNKNOWN_");
						strcpy(g_szTempString+8, tohexstr(s_sLastOpcode, nullptr, 4));
						Output(g_szTempString);
					}
						
					if(numParams = pCommand->GetNumParams())
						ProcessCommand(pOpcode, numParams, 0);
					if(numReturns = pCommand->GetNumReturns())
						ProcessCommand(pOpcode, numReturns, 1);
				}
					
				OutputNewline();
			}
			break;

		case OPCODE_TYPE_OPERATION:
			if(pOperation = pOpcode->Get<COperation>())
			{
				COperator *pOperator = pOperation->GetOperator();
				char op[MAX_OPERATOR_CHARS+1] = "";
				szncpy(op, pOperator->GetOperatorString(), sizeof(op));

				if(!pOperator->IsConditional())
				{
					if(op[1] == 0 && op[0] != OPERATOR_ASSIGN)
					{
						if(op[0] == OPERATOR_CONVERT)
						{
							// why does # have to come after = here?
							op[0] = op[1];
							op[1] = OPERATOR_ASSIGN;
						}
						else
						{
							op[1] = OPERATOR_ASSIGN;
							op[2] = 0;
						}
					}
				}

				//if(s_bNot) Output("NOT ");
				type = ReadDataType();
				uParam *p = StoreParam(type);
				OutputParam(type, p);
				Output(op);
				type = ReadDataType();
				p = StoreParam(type);
				OutputParam(type, p);

				OutputNewline();
			}
			break;

		default:;
		}
	}
	else
	{
		//if(s_sLastOpcode)
		//{
			//sprintf(g_szTempString, "Unknown opcode '0x%04X'",  s_sLastOpcode);
			//DecompileError(g_szTempString);
			//*g_szTempString = 0;

			if(!num_hex_bytes)
			{
				Output("HEX");
				OutputNewline();
			}
			else if(num_hex_bytes % MAX_HEX_BYTES_PER_LINE == 0) OutputNewline();

			//Alert(tohexstr(s_sLastOpcode, nullptr, 2));

			Output(tohexstr(s_sLastOpcode, nullptr, 2));
			//Output(" ");
			Output(tohexstr(s_sLastOpcode, nullptr, 2));
			num_hex_bytes += 2;
		//}
	}
}